package com.sk.coin.service.impl;

import com.sk.coin.constant.LoginConstant;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author: SongKun
 * @date: 2021/11/15
 * @Description:
 */
@Service
public class UserServiceDetailServiceImpl implements UserDetailsService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public UserDetails loadUserByUsername(String usermame) throws UsernameNotFoundException {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        // 区分后台管理人员与用户
        String login_type = requestAttributes.getRequest().getParameter("login_type");
        if (StringUtils.isEmpty(login_type)) {
            throw new AuthenticationServiceException("登录类型不能为空");
        }
        UserDetails userDetails = null;
        try {
            String grant_type = requestAttributes.getRequest().getParameter("grant_type");
            if (LoginConstant.REFRESH_TOKEN.equals(grant_type)) {
                usermame = adjustUsername(usermame,login_type);
            }
            switch (login_type) {
                case LoginConstant.ADMIN_TYPE:
                    userDetails = loadSysUserByUsername(usermame);
                    break;
                case LoginConstant.MEMBER_TYPE:
                    userDetails = loadMemberUserByUsername(usermame);
                    break;
                default:
                    throw new AuthenticationServiceException("暂不支持的登录方式:" + login_type);
            }
        } catch (IncorrectResultSizeDataAccessException e) {
            throw new UsernameNotFoundException("用户名" + usermame + "不存在");
        }
        return userDetails;
    }

    /**
     * 纠正用户名
     * @param usermame id
     * @param login_type
     * @return
     */
    private String adjustUsername(String usermame, String login_type) {
        if(LoginConstant.ADMIN_TYPE.equals(login_type)) {
            // 管理员
            return jdbcTemplate.queryForObject(LoginConstant.QUERY_ADMIN_USER_WITH_ID,String.class,usermame);
        }
        if (LoginConstant.MEMBER_TYPE.equals(login_type)) {
            // 会员
            return jdbcTemplate.queryForObject(LoginConstant.QUERY_MEMBER_USER_WITH_ID,String.class,usermame);
        }
        return usermame;
    }

    /**
     * 会员登录
     *
     * @param usermame
     * @return
     */
    private UserDetails loadMemberUserByUsername(String usermame) {
        return jdbcTemplate.queryForObject(LoginConstant.QUERY_MEMBER_SQL, new RowMapper<User>() {
            @Override
            public User mapRow(ResultSet rs, int rowNum) throws SQLException {
                if (rs.wasNull()) {
                    throw new UsernameNotFoundException("用户:" + usermame + "不存在");
                }
                long id = rs.getLong("id");
                String password = rs.getString("password");
                int status = rs.getInt("status");
                return new User(
                        String.valueOf(id),
                        password, status == 1,
                        true,
                        true,
                        true,
                        Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")));
            }
        }, usermame,usermame);
    }

    /**
     * 后台管理人员登录
     *
     * @param usermame
     * @return
     */
    private UserDetails loadSysUserByUsername(String usermame) {
        // (1) 使用用户名查询
        // queryForObject 查询不到会抛出异常
        return jdbcTemplate.queryForObject(LoginConstant.QUERY_ADMIN_SQL, new RowMapper<User>() {
            @Override
            public User mapRow(ResultSet resultSet, int rowNum) throws SQLException {
                if (resultSet.wasNull()) {
                    throw new UsernameNotFoundException("用户名" + usermame + "不存在");
                }
                long id = resultSet.getLong("id");
                String password = resultSet.getString("password");
                int status = resultSet.getInt("status");
                // 使用userId代替username
                return new User(
                        String.valueOf(id),
                        password,
                        status == 1,
                        true,
                        true,
                        true,
                        getSysUserPermissions(id));
            }
        }, usermame);
    }

    /**
     * 通过用户Id查询用户权限
     *
     * @param id
     * @return
     */
    private Collection<? extends GrantedAuthority> getSysUserPermissions(long id) {
        String roleCode = jdbcTemplate.queryForObject(LoginConstant.QUERY_ROLE_CODE_SQL, String.class, id);
        List<String> permission = null;
        if (LoginConstant.ADMIN_ROLE_CODE.equals(roleCode)) {
            // (1) 当用户为超管时，拥有所有的权限
            permission = jdbcTemplate.queryForList(LoginConstant.QUERY_ALL_PERMISSIONS, String.class);
        } else {
            // (2) 普通用户需要根据角色查询数据
            permission = jdbcTemplate.queryForList(LoginConstant.QUERY_PERMISSION_SQL, String.class, id);
        }
        if (CollectionUtils.isEmpty(permission)) {
            return Collections.emptySet();
        }
        return permission.stream()
                .distinct()  // 去重
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toSet());
    }
}
